package com.wzf;

import com.Constant;
import com.CustomHashMap;
import com.SerialNumber;
import com.encrypt.MD5Coder;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.xml.sax.InputSource;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;

/**
 * Created by bruce on 2016/5/22.
 */
@SuppressWarnings("unchecked")
public class WZFUtil {
        /**
         * 微支付需要的post请求
         *
         * @param url
         * @param data
         * @return
         * @throws HttpException
         * @throws IOException
         */
        public static String post(String url, String data) throws HttpException,
                IOException {

            HttpClient httpclient = new HttpClient();
            PostMethod method = new PostMethod(url);

            StringRequestEntity requestEntity = new StringRequestEntity(data,
                    "text/xml", "UTF-8");
            method.setRequestEntity(requestEntity);

            int code = httpclient.executeMethod(method);

            byte[] responseBody = null;

            if (code == HttpStatus.SC_OK) {
                Header contentEncoding = method
                        .getResponseHeader("Content-Encoding");
                if (contentEncoding != null
                        && contentEncoding.getValue().toLowerCase().indexOf("gzip") > -1) {
                    InputStream is = method.getResponseBodyAsStream();
                    GZIPInputStream gzip = new GZIPInputStream(is);
                    byte[] buf = new byte[1024];

                    int num = -1;
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();

                    while ((num = gzip.read(buf, 0, buf.length)) != -1) {
                        baos.write(buf, 0, num);
                    }
                    responseBody = baos.toByteArray();
                    baos.flush();
                    baos.close();
                    gzip.close();
                    is.close();
                } else {
                    responseBody = method.getResponseBody();
                }

                Header contentType = method.getResponseHeader("Content-Type");
                if (contentType != null) {
                    String encoding = contentType.getValue().toUpperCase();

                    Pattern pattern = Pattern.compile("CHARSET=([^;]*)");
                    Matcher matcher = pattern.matcher(encoding);
                    String charset = matcher.find() ? matcher.group(1) : null;

                    if (charset != null) {
                        responseBody = (new String(responseBody, charset))
                                .getBytes("UTF-8");
                    }
                }
            }
            String result = new String(responseBody);
            return result;
        }

        /**
         * 将map里的参数排序并拼接
         * @param params
         * @return
         * @throws UnsupportedEncodingException
         */
        public static String concatParams(Map<String, String> params)
                throws UnsupportedEncodingException {
            Object[] key_arr = params.keySet().toArray();
            Arrays.sort(key_arr);
            String str = "";

            for (Object key : key_arr) {
                String val = params.get(key);
                str += "&" + key + "=" + val;
            }

            return str.replaceFirst("&", "");
        }

        /**
         * xml转map
         * @param xml
         * @return
         * @throws DocumentException
         */
        @SuppressWarnings("rawtypes")
        public static HashMap<String, Object> xmlToMap(String xml)
                throws DocumentException {

            HashMap<String, Object> map = new HashMap<String, Object>();

            InputSource in = new InputSource(new StringReader(xml));
            in.setEncoding("UTF-8");
            SAXReader reader = new SAXReader();
            Document document = reader.read(in);
            Element root = document.getRootElement();

            Iterator eleIt = root.elementIterator();
            while (eleIt.hasNext()) {
                Element e = (Element) eleIt.next();
                map.put(e.getName(), e.getText());
            }

            return map;
        }

        /**
         * map转xml
         * @param vo
         * @param rootElement
         * @return
         */
        public static String mapToXml(Map<String, String> vo, String rootElement) {
            org.dom4j.Document doc = DocumentHelper.createDocument();
            Element body = DocumentHelper.createElement(rootElement);
            doc.add(body);
            __buildMap2xmlBody(body, vo);
            return doc.asXML();
        }

        private static void __buildMap2xmlBody(Element body, Map<String, String> vo) {
            if (vo != null) {
                Iterator<String> it = vo.keySet().iterator();
                while (it.hasNext()) {
                    String key = (String) it.next();
                    if (StringUtils.isNotEmpty(key)) {
                        Object obj = vo.get(key);
                        Element element = DocumentHelper.createElement(key);
                        if (obj != null) {
                            if (obj instanceof java.lang.String) {
                                element.setText((String) obj);
                            } else {
                                if (obj instanceof java.lang.Character
                                        || obj instanceof java.lang.Boolean
                                        || obj instanceof java.lang.Number
                                        || obj instanceof java.math.BigInteger
                                        || obj instanceof java.math.BigDecimal) {
                                    org.dom4j.Attribute attr = DocumentHelper
                                            .createAttribute(element, "type", obj
                                                    .getClass().getCanonicalName());
                                    element.add(attr);
                                    element.setText(String.valueOf(obj));
                                } else if (obj instanceof java.util.Map) {
                                    org.dom4j.Attribute attr = DocumentHelper
                                            .createAttribute(element, "type",
                                                    java.util.Map.class
                                                            .getCanonicalName());
                                    element.add(attr);
                                    __buildMap2xmlBody(element,
                                            (Map<String, String>) obj);
                                } else {
                                }
                            }
                        }
                        body.add(element);
                    }
                }
            }
        }

        public static String getRemoteIpAddr(HttpServletRequest request) {

            String ip = request.getHeader("x-forwarded-for");
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getHeader("WL-Proxy-Client-IP");
            }
            if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                ip = request.getRemoteAddr();
            }
            return ip;
        }

        public static boolean checkSign(HashMap<String, Object> data) throws UnsupportedEncodingException{

            boolean result = false;

            Map<String, String> params = new HashMap<String, String>();

            if (data == null || data.size() <= 0) {
                return result;
            }

            for (String key : data.keySet()) {
                String value = (String) data.get(key);
                if (value == null || value.equals("")) {
                    continue;
                }
                params.put(key, value);
            }

            String sign = params.get("sign");
            params.remove("sign");

            String content = WZFUtil.concatParams(params) + "&key=" + Constant.key_wx + "";
            if(MD5Coder.encode(content).toUpperCase().equals(sign)){
                return true;
            }
            return result;
        }

        public static void main(String[] args) throws IOException,
                DocumentException {

            HashMap<String, String> map = new HashMap<String, String>();

            map.put("appid", Constant.appid_wx);
            map.put("mch_id", Constant.mch_id_wx);
            map.put("nonce_str", SerialNumber.getRandomString(16));
            map.put("body", "李子园");
            map.put("attach", "259");
            map.put("out_trade_no", "PNoojdbu33hadg");
            map.put("total_fee", "1");
            map.put("spbill_create_ip", "10.12.14.2");
            map.put("notify_url", Constant.WEB_MANAGER_URL + "/api/shopOrder/payment/wzfPush");
            map.put("trade_type", "APP");

            String params = WZFUtil.concatParams(map) + "&key=" + Constant.key_wx + "";
            String sign = MD5Coder.encode(params).toUpperCase();

            map.put("sign", sign);

            String xml = WZFUtil.mapToXml(map, "xml");
            map.clear();
            String result = WZFUtil.post(Constant.pay_url_wx, xml);
            HashMap<String, Object> maps = WZFUtil.xmlToMap(result);
            CustomHashMap<String, Object> item = CustomHashMap.convert(maps);

            System.out.println(item.getString("prepay_id"));
        }

}
